'''
	解析抽象语法树
'''
# 基础节点访问器的类
from interpreters.base_node_visitor import NodeVisitor
# 符号表
from symbol.symbol_table import SymbolTable
# 作用域符号表
from symbol.scoped_symbol_table import ScopedSymbolTable
# 调用栈 , 活动记录
from interpreters.call_stack_and_activation_records import CallStack,ActivationRecord,ARType
# 语义分析器
from interpreters.semantic_analyzer import SemanticAnalyzer
#公共库
from common import *
#错误
from error.error import syntax_error,type_error
'''
	collections是Python内建的一个集合模块，提供了许多有用的集合类和方法。
	print(dir(collections))
'''
from collections import OrderedDict



# 解释器类
class Interpreter(NodeVisitor):

	def __init__(self,tree):
		# 获取参数AST
		self.tree = tree
		# 调用堆栈
		self.call_stack = CallStack()

	# 执行解释的方法
	def interpret(self):
		tree = self.tree  # 获取AST
		if tree is None:  # 如果AST不存在
			return ''  # 返回空字符串
		return self.visit(tree)  # 否则访问AST

	# 添加访问程序的方法
	def visit_Program(self, node):
		#进入程序PROGRAM
		program_name = node.name

		#创建当前活动记录PROGRAM
		ar = ActivationRecord(
			name=program_name,
			type=ARType.PROGRAM,
			nesting_level=1,
		)

		# 当前活动记录入栈
		self.call_stack.push(ar)
		# 访问语句块
		self.visit(node.block)
		#当前活动记录出栈
		self.call_stack.pop()

	# 添加访问语句块的方法
	def visit_Block(self, node):
		# 遍历文件导入列表
		for importfile in node.import_file:
			self.visit(importfile)  # 访问文件导入
		# 遍历声明列表
		for declaration in node.declarations:
			self.visit(declaration)  # 访问声明
		# 访问复合语句
		self.visit(node.compound_statement)
	# 访问复合语句节点
	def visit_Compound(self,node):
		# 遍历复合语句节点的子节点
		for child in node.children:
			# 访问子节点
			self.visit(child);

	# 访问赋值语句节点
	def visit_Assign(self,node):
		# 获取变量名称
		var_name=node.left.name;
		var_value=self.visit(node.right);
		ar = self.call_stack.peek()  #获取调用栈的栈顶
		# 以变量名称为键添加变量值到栈顶活动记录ActivationRecord的members字典
		ar[var_name] = var_value
		print('visit_Assign:',ar)
		print('visit_Assign:',ar)

	# 访问加法赋值语句节点
	def visit_PlusAssign(self,node):
		# 获取变量名称
		var_name=node.left.name;
		var_value=self.visit(node.right);
		ar = self.call_stack.peek()  #获取调用栈的栈顶
		# 以变量名称为键添加变量值到栈顶活动记录ActivationRecord的members字典
		ar[var_name] = var_value
	# 访问减法赋值语句节点
	def visit_MinusAssign(self,node):
		# 获取变量名称
		var_name=node.left.name;
		var_value=self.visit(node.right);
		ar = self.call_stack.peek()  #获取调用栈的栈顶
		# 以变量名称为键添加变量值到栈顶活动记录ActivationRecord的members字典
		ar[var_name] = var_value
	# 访问乘法赋值语句节点
	def visit_MulAssign(self,node):
		# 获取变量名称
		var_name=node.left.name;
		var_value=self.visit(node.right);
		ar = self.call_stack.peek()  #获取调用栈的栈顶
		# 以变量名称为键添加变量值到栈顶活动记录ActivationRecord的members字典
		ar[var_name] = var_value
	# 访问除法赋值语句节点
	def visit_DivAssign(self,node):
		# 获取变量名称
		var_name=node.left.name;
		# 以变量名称为键添加变量值到符号表
		var_value=self.visit(node.right);
		ar = self.call_stack.peek()  #获取调用栈的栈顶
		# 以变量名称为键添加变量值到栈顶活动记录ActivationRecord的members字典
		ar[var_name] = var_value

	# 访问变量节点
	def visit_Variable(self,node):
		# 获取变量名称
		var_name=node.name;
		# 获取变量值
		ar = self.call_stack.peek()  #获取调用栈的栈顶
		# 从栈顶活动记录ActivationRecord的members字典获取变量值（变量名称为键）
		value = ar.get(var_name)
		# 如果没有返回值（变量不存在）
		if value is None:
			raise NameError(f'错误的标识符：{repr(var_name)}')  # 抛出异常
		else:
			# 否则
			# 返回变量值
			return value;

	# 访问空语句节点
	def visit_NoOperator(self,node):
		pass;


	# 访问运算符类节点
	def visit_BinaryOperator(self,node):
		# 判断节点类型是否为加法
		if node.operator.tokenType==PLUS:
			# 分别访问左侧和右侧的token，将获取的值进行加法运算，并返回结果。
			return self.visit(node.left) + self.visit(node.right);
		elif node.operator.tokenType==MINUS:
			return self.visit(node.left) - self.visit(node.right);
		elif node.operator.tokenType==MUL:
			return self.visit(node.left) * self.visit(node.right);
		elif node.operator.tokenType==DIV:
			return self.visit(node.left) // self.visit(node.right);
		elif node.operator.tokenType==EQUAL:
			return self.visit(node.left) == self.visit(node.right);
		elif node.operator.tokenType==NOTEQUAL:
			return self.visit(node.left) != self.visit(node.right);

		elif node.operator.tokenType==AND:
			return self.visit(node.left) and self.visit(node.right);
		elif node.operator.tokenType==OR:
			return self.visit(node.left) or self.visit(node.right);
		elif node.operator.tokenType==NOT:
			return not self.visit(node.right);

		self.visit(node.left)  # 访问左侧节点
		self.visit(node.right)  # 访问右侧节点

	def visit_ComparisonOperation(self,node):
		variateLeft=self.visit(node.left);
		variateRight=self.visit(node.right);
		if node.operator.tokenType==GREATER_THAN:
			if typeof(variateLeft)!='int' and typeof(variateLeft)!='float':
				type_error('类型不对不支持比较运算！');
			elif typeof(variateRight)!='int' and typeof(variateRight)!='float':
				type_error('类型不对不支持比较运算！');
			return variateLeft > variateRight;
		elif node.operator.tokenType==LESS_THAN:
			if typeof(variateLeft)!='int' and typeof(variateLeft)!='float':
				type_error('类型不对不支持比较运算！');
			elif typeof(variateRight)!='int' and typeof(variateRight)!='float':
				type_error('类型不对不支持比较运算！');
			return variateLeft < variateRight;
		elif node.operator.tokenType==GREATER_THAN_EQUAL:
			if typeof(variateLeft)!='int' and typeof(variateLeft)!='float':
				type_error('类型不对不支持比较运算！');
			elif typeof(variateRight)!='int' and typeof(variateRight)!='float':
				type_error('类型不对不支持比较运算！');
			return variateLeft >= variateRight;
		elif node.operator.tokenType==LESS_THAN_EQUAL:
			if typeof(variateLeft)!='int' and typeof(variateLeft)!='float':
				type_error('类型不对不支持比较运算！');
			elif typeof(variateRight)!='int' and typeof(variateRight)!='float':
				type_error('类型不对不支持比较运算！');
			return variateLeft <= variateRight;

	# 访问数字节点
	def visit_Num(self,node):
		return node.value;

	# 访问字符串节点
	def visit_Str(self,node):
		return node.value;

	def visit_Boolean(self,node):
		return node.value;

	# 访问一元运算符类型节点的方法
	def visit_UnaryOperator(self,node):
		# 如果运算符类型是加号
		if node.operator.tokenType==PLUS:
			return +self.visit(node.expression);
		if node.operator.tokenType==MINUS:
			return -self.visit(node.expression);

	# 逻辑运算
	def visit_LogicWron(self,node):
		if node.operator.tokenType==NOT:
			return not self.visit(node.expression);
		if node.operator.tokenType==NOT:
			return not self.visit(node.expression);
		if node.operator.tokenType==NOT:
			return not self.visit(node.expression);
	# 布尔运算
	def visit_BooleanOperation(self,node):
		value=self.visit(node.expression);
		if value=='true':
			return True;
		if value=='false':
			return False;


	# 添加访问变量声明的方法
	def visit_VarDecl(self, node):
		# 获取变量名称
		var_name=node.var_node.name;
		# # 以变量名称为键添加变量值到符号表
		types=self.visit(node.type_node);
		ar = self.call_stack.peek()  #获取调用栈的栈顶
		# 以变量名称为键添加变量值到栈顶活动记录ActivationRecord的members字典
		ar[var_name] = types.value

	# 添加访问类型的方法
	def visit_Type(self, node):
		return node;


	# 添加文件导入的方法
	def visit_Import(self, node):
		# 访问语句块
		path=self.visit(node.import_node)
		#文件路径
		# print(path)
		# with open(path+'.y','r',encoding='utf-8') as f:
		# content = f.read()

	#条件控制节点
	def visit_If(self, node):
		#判断条件节点的值
		con=self.visit(node.condition)
		if con:
			#条件成立,则以then节点为准
			self.visit(node.then_node)
		else:
			self.visit(node.else_node)

	def visit_For(self, node):  # 循环控制节点
		start = self.visit(node.start_node.right)  # 获取循环体变量的开始值(它是一个ASSIGN赋值节点)
		end = self.visit(node.end_node)  ##获取循环体变量的终止值
		var_name = node.start_node.left.name  # 获取循环变量名称
		ar = self.call_stack.peek()  # 获取调用栈的栈顶,以达到更新循环变量的目的
		for x in range(start, end + 1):
			ar[var_name] = x  # 循环变量要不断累加增长，更新后写入到栈顶的当前活动记录
			self.visit(node.do_node)  # 执行循环体内的语句

	# 添加函数参数
	def visit_Param(self, node):
		pass

	# 添加访问过程声明的方法
	def visit_Function(self, node):
		# self.visit(node)
		pass

	# 函数调用
	def visit_Call(self, node):
		print(node.viewTree())
		#进入函数调用FUNCTION
		proc_name = node.proc_name
		print(f'>>>>>>进入函数调用: FUNCTION {proc_name}')
		#创建当前活动记录PROCEDURE
		ar = ActivationRecord(
			name=proc_name,
			type=ARType.CALL,
			# nesting_level=node.proc_symbol.scope_level + 1,
			nesting_level=1,
		)
		# proc_symbol = node.proc_symbol  #取到当前节点的过程符号
		# formal_params = proc_symbol.formal_params #取到形式参数列表
		# actual_params = node.actual_params #取到实际参数列表
		# print(actual_params);
		# # #把实际参数的值存入到对应的形式参数里
		# for param_symbol, argument_node in zip(formal_params, actual_params):
		# 	#遍历每个实际参数节点的值，将结果写入对应形式参数位置
		# 	ar[param_symbol.name] = self.visit(argument_node)
		print(f'>>>>>>实参传递值到形参<<<<<<')

		self.call_stack.push(ar) #当前活动记录入栈
		print(str(self.call_stack))#打印调用栈

		print(f'>>>>>>执行调用<<<<<<')
		# self.visit(proc_symbol.block_ast)  #访问PROCEDURE或FUNCTION下的语句块Block节点
		print(str(self.call_stack))#打印调用栈

		#离开当前活动记录
		print(f'<<<<<<离开调用: FUNCTION {proc_name}')
		self.call_stack.pop()   #当前活动记录出栈
		print(str(self.call_stack))#打印调用栈
		try:
			returnvalue=ar[proc_name]
			print('这是一次函数调用,调用返回值:',returnvalue)
			return returnvalue
		except:
			print('这是一次过程调用,没有返回值')



	# ======================== start 内置函数 ====================== #

	#打印输出
	def visit_Print(self, node):
		for node in node.params:
			print(self.visit(node),end='')
		print('\t')

	#字符串长度
	def visit_Length(self, node):
		print(len(self.visit(node.params)))

	#获取变量类型
	def visit_GetType(self, node):
		print(typeof(self.visit(node.params)))








	# ======================== end 内置函数 ====================== #

